/**
 * 
 */
package org.wolf.core.schema;

import java.io.IOException;
import java.io.Reader;
import java.io.Serializable;
import java.util.Map;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.Tokenizer;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Index;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.FieldComparatorSource;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TermRangeQuery;
import org.wolf.core.sort.MissingComparatorSource;

/**
 * @author 何小锋
 * 
 */
public abstract class FieldType implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * 额外的参数
	 */
	protected Map<String, String> args;

	/**
	 * 是否分词
	 */
	protected boolean tokenized;

	/**
	 * 是否多值
	 */
	protected boolean multiValued;

	/**
	 * 是否索引
	 */
	protected boolean indexed;

	/**
	 * 是否存储
	 */
	protected boolean stored;

	/**
	 * 是否必须
	 */
	protected boolean required;

	/**
	 * 是否二进制
	 */
	protected boolean binary;

	/**
	 * 是否存储词条向量
	 */
	protected boolean storeTermVector;

	/**
	 * 是否存储词条位置
	 */
	protected boolean storeTermPositions;

	/**
	 * 是否存储词条偏移量
	 */
	protected boolean storeTermOffsets;

	/**
	 * 是否忽略规范
	 */
	protected boolean omitNorms;

	/**
	 * 是否忽略词频
	 */
	protected boolean omitTf;

	/**
	 * 没值的时候排序最前面
	 */
	protected boolean sortMissingFirst;

	/**
	 * 没值的时候排序最后面
	 */
	protected boolean sortMissingLast;

	/**
	 * 多态字段
	 */
	protected boolean polyField;

	/**
	 * 默认的分词器
	 */
	protected Analyzer analyzer = new DefaultAnalyzer(256);

	/**
	 * 查询的分词器
	 */
	protected Analyzer queryAnalyzer = analyzer;

	protected FieldComparatorSource comparatorSource = new MissingComparatorSource();

	public Map<String, String> getArgs() {
		return args;
	}

	public void setArgs(Map<String, String> args) {
		this.args = args;
	}

	public boolean isTokenized() {
		return tokenized;
	}

	public void setTokenized(boolean tokenized) {
		this.tokenized = tokenized;
	}

	public boolean isMultiValued() {
		return multiValued;
	}

	public void setMultiValued(boolean multiValued) {
		this.multiValued = multiValued;
	}

	public boolean isIndexed() {
		return indexed;
	}

	public void setIndexed(boolean indexed) {
		this.indexed = indexed;
	}

	public boolean isStored() {
		return stored;
	}

	public void setStored(boolean stored) {
		this.stored = stored;
	}

	public boolean isRequired() {
		return required;
	}

	public void setRequired(boolean required) {
		this.required = required;
	}

	public boolean isBinary() {
		return binary;
	}

	public void setBinary(boolean binary) {
		this.binary = binary;
	}

	public boolean isStoreTermVector() {
		return storeTermVector;
	}

	public void setStoreTermVector(boolean storeTermVector) {
		this.storeTermVector = storeTermVector;
	}

	public boolean isStoreTermPositions() {
		return storeTermPositions;
	}

	public void setStoreTermPositions(boolean storeTermPositions) {
		this.storeTermPositions = storeTermPositions;
	}

	public boolean isStoreTermOffsets() {
		return storeTermOffsets;
	}

	public void setStoreTermOffsets(boolean storeTermOffsets) {
		this.storeTermOffsets = storeTermOffsets;
	}

	public boolean isOmitNorms() {
		return omitNorms;
	}

	public void setOmitNorms(boolean omitNorms) {
		this.omitNorms = omitNorms;
	}

	public boolean isOmitTf() {
		return omitTf;
	}

	public void setOmitTf(boolean omitTf) {
		this.omitTf = omitTf;
	}

	public boolean isSortMissingFirst() {
		return sortMissingFirst;
	}

	public void setSortMissingFirst(boolean sortMissingFirst) {
		this.sortMissingFirst = sortMissingFirst;
	}

	public boolean isSortMissingLast() {
		return sortMissingLast;
	}

	public void setSortMissingLast(boolean sortMissingLast) {
		this.sortMissingLast = sortMissingLast;
	}

	public boolean isPolyField() {
		return polyField;
	}

	public void setPolyField(boolean polyField) {
		this.polyField = polyField;
	}

	public Analyzer getAnalyzer() {
		return analyzer;
	}

	public void setAnalyzer(Analyzer analyzer) {
		this.analyzer = analyzer;
	}

	public Analyzer getQueryAnalyzer() {
		return queryAnalyzer;
	}

	public void setQueryAnalyzer(Analyzer queryAnalyzer) {
		this.queryAnalyzer = queryAnalyzer;
	}

	/**
	 * 转换成内部字符串
	 * 
	 * @param value
	 * @return
	 */
	public String toInternal(Object value) {
		if (value == null)
			return null;
		return value.toString();
	}

	/**
	 * 转换成外部对象
	 * 
	 * @param f
	 * @return
	 */
	public Object toExternal(Fieldable f) {
		return f.stringValue();
	}

	/**
	 * 创建字段
	 * 
	 * @param field
	 * @param value
	 * @param boost
	 * @return
	 */
	public Fieldable[] createFields(DocField field, Object value, float boost) {
		Field f = createField(field, value, boost);
		return f == null ? new Fieldable[] {} : new Fieldable[] { f };
	}

	/**
	 * 创建字段
	 * 
	 * @param field
	 * @param value
	 * @param boost
	 * @return
	 */
	public Field createField(DocField field, Object value, float boost) {
		if (!field.isIndexed() && !field.isStored()) {
			return null;
		}
		String val = toInternal(value);
		if (val == null)
			return null;

		Field.TermVector ftv = Field.TermVector.NO;
		if (field.isStoreTermPositions() && field.isStoreTermOffsets())
			ftv = Field.TermVector.WITH_POSITIONS_OFFSETS;
		else if (field.isStoreTermPositions())
			ftv = Field.TermVector.WITH_POSITIONS;
		else if (field.isStoreTermOffsets())
			ftv = Field.TermVector.WITH_OFFSETS;
		else if (field.isStoreTermVector())
			ftv = Field.TermVector.YES;
		Index findexed = field.isIndexed() ? (field.isTokenized() ? Field.Index.ANALYZED
				: Field.Index.NOT_ANALYZED)
				: Field.Index.NO;
		Store fstored = field.isStored() ? Field.Store.YES : Field.Store.NO;

		return createField(field.getName(), val, fstored, findexed, ftv,
				field.isOmitNorms(), field.isOmitTf(), boost);
	}

	/**
	 * 创建字段
	 * 
	 * @param name
	 * @param val
	 * @param storage
	 * @param index
	 * @param vec
	 * @param omitNorms
	 * @param omitTFPos
	 * @param boost
	 * @return
	 */
	protected Field createField(String name, String val, Field.Store storage,
			Field.Index index, Field.TermVector vec, boolean omitNorms,
			boolean omitTFPos, float boost) {
		Field f = new Field(name, val, storage, index, vec);
		f.setOmitNorms(omitNorms);
		f.setOmitTermFreqAndPositions(omitTFPos);
		f.setBoost(boost);
		return f;
	}

	/**
	 * 获取排序字段
	 * 
	 * @param field
	 * @param reverse
	 * @return
	 */
	public SortField getSortField(DocField field, boolean reverse) {
		if (!field.isIndexed()) {
			throw new UnsupportedOperationException(
					"can not sort on unindexed field: " + field.getName());
		}
		if (field.isMultiValued()) {
			throw new UnsupportedOperationException(
					"can not sort on multivalued field: " + field.getName());
		}

		return createSortField(field, reverse);
	}

	/**
	 * 创建排序字段
	 * 
	 * @param field
	 * @param reverse
	 * @return
	 */
	protected SortField createSortField(DocField field, boolean reverse) {
		if (field.isSortMissingLast() != null
				&& field.isSortMissingLast().booleanValue() && !reverse
				|| field.isSortMissingFirst() != null
				&& field.isSortMissingFirst().booleanValue() && reverse)
			return new SortField(field.getName(), comparatorSource);
		return new SortField(field.getName(), SortField.STRING, reverse);
	}

	/**
	 * 获取范围查询
	 * 
	 * @param parser
	 * @param field
	 * @param min
	 * @param max
	 * @param minInclusive
	 * @param maxInclusive
	 * @return
	 */
	public Query getRangeQuery(QueryParser parser, DocField field, String min,
			String max, boolean minInclusive, boolean maxInclusive) {
		return new TermRangeQuery(field.getName(), min == null ? null
				: toInternal(min), max == null ? null : toInternal(max),
				minInclusive, maxInclusive);
	}

	/**
	 * 获取字段查询
	 * 
	 * @param parser
	 * @param field
	 * @param value
	 * @return
	 */
	public Query getFieldQuery(QueryParser parser, DocField field, String value) {
		return new TermQuery(new Term(field.getName(), toInternal(value)));
	}

	/**
	 * 默认分词器
	 * 
	 * @author 何小锋
	 * 
	 */
	protected final class DefaultAnalyzer extends Analyzer {
		final int maxChars;

		public DefaultAnalyzer(int maxChars) {
			this.maxChars = maxChars;
		}

		@Override
		public TokenStream tokenStream(String fieldName, Reader reader) {
			Tokenizer tokenizer = new Tokenizer(reader) {
				final char[] cbuf = new char[maxChars];
				final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class);
				final OffsetAttribute offsetAtt = addAttribute(OffsetAttribute.class);

				@Override
				public boolean incrementToken() throws IOException {
					clearAttributes();
					int n = input.read(cbuf, 0, maxChars);
					if (n <= 0)
						return false;
					String s = toInternal(new String(cbuf, 0, n));
					termAtt.setEmpty().append(s);
					offsetAtt.setOffset(correctOffset(0), correctOffset(n));
					return true;
				}
			};

			return tokenizer;
		}
	}

}
